package dtdrelacional;

import java.util.*;
import java.io.*;

public class GeneradorScriptEsquema {

  HashMap<String, TablaSQL> tablasSQL;
  Writer archTablas;
  Writer archTablasDrops;
  Writer archForaneas;
  Writer archForaneasDrops;

  public GeneradorScriptEsquema(HashMap<String, TablaSQL> tablasSQL) {
    this.tablasSQL = tablasSQL;
  }

  public void generar(String nombreArchTablas, String nombreArchTablasDrops,
          String nombreArchForaneas, String nombreArchForaneasDrops) {
    try {
      archTablas = new FileWriter(nombreArchTablas);
      archTablasDrops = new FileWriter(nombreArchTablasDrops);
      archForaneas = new FileWriter(nombreArchForaneas);
      archForaneasDrops = new FileWriter(nombreArchForaneasDrops);
    } catch (IOException ex) {
      System.err.println("Error al abrir archivos de esquema: "
              + nombreArchTablas + ", " + nombreArchTablasDrops + ", "
              + nombreArchForaneas + ", " + nombreArchForaneasDrops);
      return;
    }

    try {
      escribirComenzar();
    } catch (IOException ex) {
      System.err.println("Error al escribir en archivos de esquema: "
              + nombreArchTablas + ", " + nombreArchTablasDrops + ", "
              + nombreArchForaneas + ", " + nombreArchForaneasDrops);
    }

    try {
      archTablas.close();
      archTablasDrops.close();
      archForaneas.close();
      archForaneasDrops.close();
    } catch (IOException ex) {
      System.err.println("Error al cerrar archivos de esquema: "
              + nombreArchTablas + ", " + nombreArchTablasDrops + ", "
              + nombreArchForaneas + ", " + nombreArchForaneasDrops);
    }
  }

  private void escribirComenzar() throws IOException {
    
//    escribirEncabezados();
    
    Iterator<TablaSQL> iterTablas = tablasSQL.values().iterator();
    while (iterTablas.hasNext()) {
      escribirTabla(iterTablas.next());
    }
  }

  private void escribirTabla(TablaSQL tablaSQL) throws IOException {

    archTablas.write("CREATE TABLE " + tablaSQL.getNombre() + "(\n");

    escribirColumnas(tablaSQL);
    escribirClavesForaneas(tablaSQL);
    escribirClavesPrimarias(tablaSQL);

    // termina la tabla con parentesis y dos saltos de linea
    archTablas.write(");\n\n");

    archTablasDrops.write("DROP TABLE " + tablaSQL.getNombre() + ";\n\n");
  }

  private void escribirColumnas(TablaSQL tablaSQL) throws IOException {
    Iterator<ColumnaSQL> iteColumnas = tablaSQL.getColumnas().iterator();
    ColumnaSQL columna;
    while (iteColumnas.hasNext()) {
      columna = iteColumnas.next();

      archTablas.write("\t" + columna.getNombre() + " VARCHAR(255)");
      if (columna.isRequerida()) {
        archTablas.write(" NOT NULL");
      }
      archTablas.write(",\n");
    }
  }

  private void escribirClavesPrimarias(TablaSQL tablaSQL) throws IOException {

    archTablas.write("\tPRIMARY KEY (");

    Iterator<ColumnaSQL> iteColumnas = tablaSQL.getColumnasPrimarias().iterator();
    ColumnaSQL columna;
    while (iteColumnas.hasNext()) {
      columna = iteColumnas.next();

      archTablas.write(columna.getNombre());
      if (iteColumnas.hasNext()) {
        archTablas.write(",");
      }
    }
    archTablas.write(")\n");
  }

  private void escribirClavesForaneas(TablaSQL tabla) throws IOException {

    Iterator<String> iteTablasForaneas = tabla.getNombresTablasForaneas().iterator();
    String nombreTablaForanea;
    while (iteTablasForaneas.hasNext()) {
      nombreTablaForanea = iteTablasForaneas.next();
      archForaneas.write("ALTER TABLE " + tabla.getNombre() + "\n");
      archForaneasDrops.write("ALTER TABLE " + tabla.getNombre() + "\n");
      escribirClaveForanea(nombreTablaForanea,
              tabla.getColumnasForaneasATabla(nombreTablaForanea));
    }
  }

  private void escribirClaveForanea(String nombreTablaForanea,
          HashSet<ColumnaSQL> columnas) throws IOException {

    Iterator<ColumnaSQL> iteColumnas = columnas.iterator();
    ColumnaSQL columna = iteColumnas.next();

    String referencias = columna.getNombre();
    String referenciadas = columna.getDatosForanea()[1];
    while (iteColumnas.hasNext()) {
      columna = iteColumnas.next();
      referencias += "," + columna.getNombre();
      referenciadas += "," + columna.getDatosForanea()[1];
    }

    archForaneas.write("\tADD CONSTRAINT fk_" + nombreTablaForanea
            + " FOREIGN KEY (" + referencias + ") " + "REFERENCES "
            + nombreTablaForanea + "(" + referenciadas + ");\n\n");

    archForaneasDrops.write("\tDROP CONSTRAINT fk_" + nombreTablaForanea + ";\n\n");
  }
}
